namespace TfsReportRenderer.ImageAdder
{
    using System;
    using System.Globalization;
    using System.IO;
    using System.Linq;

    using DocumentFormat.OpenXml;
    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Spreadsheet;

    /// <summary>
    /// The Open XML abstraction for inserting images.
    /// See: <a href="http://user239.blogspot.de/2011/03/how-to-insert-image-to-excel-document.html"> How to insert an image into an Excel document </a>
    /// </summary>
    public static class OpenXmlTool
    {
        public static void InsertImage(WorksheetPart worksheetPart, string imageFileName, int colNumber, int rowNumber, int maxWidth, int maxHeight, int offsetX, int offsetY)
        {
            worksheetPart.MustNotBeNull("sImagePath");

            var drawingsPart = worksheetPart.DrawingsPart ?? worksheetPart.AddNewPart<DrawingsPart>();

            if (!worksheetPart.Worksheet.ChildElements.OfType<Drawing>().Any())
            {
                worksheetPart.Worksheet.AppendChild(new Drawing { Id = worksheetPart.GetIdOfPart(drawingsPart) });
            }

            if (drawingsPart.WorksheetDrawing == null)
            {
                drawingsPart.WorksheetDrawing = new DocumentFormat.OpenXml.Drawing.Spreadsheet.WorksheetDrawing();
            }

            var worksheetDrawing = drawingsPart.WorksheetDrawing;
            var imagePart = drawingsPart.AddImagePart(ImagePartType.Png);

            using (var stream = new FileStream(imageFileName, FileMode.Open))
            {
                imagePart.FeedData(stream);
            }

            var positioningEmu = new ImagePositioningEmu(imageFileName, maxWidth, maxHeight, offsetX, offsetY);

            var extentsCx = positioningEmu.Width;
            long extentsCy = positioningEmu.Height;

            if (extentsCy > positioningEmu.MaxHeight || extentsCx > positioningEmu.MaxWidth)
            {
                var scaleX = (double)extentsCx / positioningEmu.MaxWidth;
                var scaleY = (double)extentsCy / positioningEmu.MaxHeight;
                var scale = Math.Max(scaleX, scaleY);
                extentsCx = (int)(extentsCx / scale);
                extentsCy = (int)(extentsCy / scale);
            }

            var colOffset = positioningEmu.OffsetX;
            var rowOffset = positioningEmu.OffsetY;

            var nvps = worksheetDrawing.Descendants<DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualDrawingProperties>();
            var nvpId = nvps.Any() 
                            ? (UInt32Value)worksheetDrawing.Descendants<DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualDrawingProperties>().Max(p => p.Id.Value) + 1 
                            : 1U;

            var oneCellAnchor = new DocumentFormat.OpenXml.Drawing.Spreadsheet.OneCellAnchor(
                new DocumentFormat.OpenXml.Drawing.Spreadsheet.FromMarker
                    {
                        ColumnId = new DocumentFormat.OpenXml.Drawing.Spreadsheet.ColumnId((colNumber - 1).ToString(CultureInfo.InvariantCulture)),
                        RowId = new DocumentFormat.OpenXml.Drawing.Spreadsheet.RowId((rowNumber - 1).ToString(CultureInfo.InvariantCulture)),
                        ColumnOffset = new DocumentFormat.OpenXml.Drawing.Spreadsheet.ColumnOffset(colOffset.ToString(CultureInfo.InvariantCulture)),
                        RowOffset = new DocumentFormat.OpenXml.Drawing.Spreadsheet.RowOffset(rowOffset.ToString(CultureInfo.InvariantCulture))
                    },
                new DocumentFormat.OpenXml.Drawing.Spreadsheet.Extent { Cx = extentsCx, Cy = extentsCy },
                new DocumentFormat.OpenXml.Drawing.Spreadsheet.Picture(
                    new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualPictureProperties(
                        new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualDrawingProperties { Id = nvpId, Name = "Picture " + nvpId, Description = "something" },
                        new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualPictureDrawingProperties(new DocumentFormat.OpenXml.Drawing.PictureLocks { NoChangeAspect = false })),
                    new DocumentFormat.OpenXml.Drawing.Spreadsheet.BlipFill(
                        new DocumentFormat.OpenXml.Drawing.Blip { Embed = drawingsPart.GetIdOfPart(imagePart), CompressionState = DocumentFormat.OpenXml.Drawing.BlipCompressionValues.Print },
                        new DocumentFormat.OpenXml.Drawing.Stretch(new DocumentFormat.OpenXml.Drawing.FillRectangle())),
                    new DocumentFormat.OpenXml.Drawing.Spreadsheet.ShapeProperties(
                        new DocumentFormat.OpenXml.Drawing.Transform2D(
                            new DocumentFormat.OpenXml.Drawing.Offset { X = 0, Y = 0 },
                            new DocumentFormat.OpenXml.Drawing.Extents { Cx = extentsCx, Cy = extentsCy }),
                        new DocumentFormat.OpenXml.Drawing.PresetGeometry { Preset = DocumentFormat.OpenXml.Drawing.ShapeTypeValues.Rectangle })),
                new DocumentFormat.OpenXml.Drawing.Spreadsheet.ClientData());

            worksheetDrawing.AppendChild(oneCellAnchor);
        }
    }
}